/*
	Copyright 2009 Benjamin Vedder	vedder87@gmail.com
	
	This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    */

package com.google.code.retrobox.editor.tiles;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;


import javax.swing.*;
import javax.swing.border.EtchedBorder;

import com.google.code.retrobox.editor.MainWindow;
import com.google.code.retrobox.editor.commons.ColorButton;
import com.google.code.retrobox.editor.commons.Tools;
import com.google.code.retrobox.editor.commons.dialog.ColorReplaceDialog;
import com.google.code.retrobox.editor.dataCollections.TileData;
import com.google.code.retrobox.editor.dataCollections.TileSet;

public class TileEditor extends JPanel implements ActionListener {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public static final int 	TILES_X = 4,
								TILES_Y = 2;
	
	private int currentIndex = 0;
	
	private TileSet tileset;
	
	public TileSet getTileset() {
		return tileset;
	}

	public void setTileset(TileSet tileset) {
		this.tileset = tileset;
	}

	private TileSetPanel tilesetPanel;
	
	private JFrame parent = null;
	private List<SingleTileRenderer> tileList = new ArrayList<SingleTileRenderer>();
	private List<JRadioButton> tileRadioButtons = new ArrayList<JRadioButton>();
	
	private ButtonGroup tileButtonGroup = new ButtonGroup();
	
	private ColorReplaceDialog replaceDialog;
	
	// Components
	private JPanel tool1Panel = new JPanel(new BorderLayout());
	private JPanel tool2Panel = new JPanel(new BorderLayout());
	
	private JPanel colorBar = new JPanel(new GridLayout(2, 8));
	private JPanel tilePanel = new JPanel(new BorderLayout());
	private JPanel tileMatrix = new JPanel(new GridLayout(TILES_Y, TILES_X));
	private JPanel currentColor = new JPanel();

	private JButton replaceColorButton = new JButton("Replace all colors...");
	private JButton addTilesButton = new JButton("Add tiles...");
	private JButton removeTilesButton = new JButton("Remove tiles...");
	private JButton flipTileHorizontalButton = new JButton("Flip tile horizontal");
	private JButton flipTileVerticalButton = new JButton("Flip tile vertical");
	private JButton copyTileButton = new JButton("Copy tile");
	private JButton pasteTileButton = new JButton("Paste tile");

	private JButton saveAllButton = new JButton("Save all");
	
	private JCheckBox autoChangeTileBox = new JCheckBox("Auto-switch selected tile", true);
	
	// Collision
	private JPanel colPanel = new JPanel(new GridLayout(8, 1));
	
	private JCheckBox nColBox = new JCheckBox("North");
	private JCheckBox sColBox = new JCheckBox("South");
	private JCheckBox wColBox = new JCheckBox("West");
	private JCheckBox eColBox = new JCheckBox("East");
	private JCheckBox jumpColBox = new JCheckBox("Jump");
	private JCheckBox waterColBox = new JCheckBox("Water");
	
	private JButton saveColButton = new JButton("Save  ");
	private JLabel colIndexLabel = new JLabel("");

	private char[] pixelData;
	
	
	
	public TileEditor(TileSet ts, JFrame parent) {
		tileset = ts;
		tilesetPanel = new TileSetPanel(ts);
		this.parent = parent;
		
		init();
	}
	
	private void init() {
		setLayout(new BorderLayout());
		
		tilesetPanel.addActionListener(this);
		replaceColorButton.addActionListener(this);
		addTilesButton.addActionListener(this);
		removeTilesButton.addActionListener(this);
		flipTileHorizontalButton.addActionListener(this);
		flipTileVerticalButton.addActionListener(this);
		copyTileButton.addActionListener(this);
		pasteTileButton.addActionListener(this);
		saveAllButton.addActionListener(this);
		
		// ------------- Add color palette ---------------- //
		for (int i = 0;i < 16;i++) {
			ColorButton b = new ColorButton();
			b.setOpaque(true);
			b.setBackground(Tools.getColor(i));
			b.setPreferredSize(new Dimension(32, 32));
			
			b.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					ColorButton b = (ColorButton)arg0.getSource();
					currentColor.setBackground(b.getBackground());
				}
			});
			
			colorBar.add(b);
		}
		
		// ----------------------------------------------- //
		
		tool1Panel.add(colorBar, BorderLayout.CENTER);
		
		JPanel tmpPanel = new JPanel(new BorderLayout());
		tmpPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
		
		currentColor.setOpaque(true);
		currentColor.setBackground(Tools.getColor(0));
		currentColor.setPreferredSize(new Dimension(80, 80));
		tmpPanel.add(currentColor, BorderLayout.CENTER);
		
		tool1Panel.add(tmpPanel, BorderLayout.EAST);
		tool1Panel.add(tilesetPanel, BorderLayout.WEST);
		
		// ------------------- Add tile renderers ---------------- //
		for (int i = 0;i < (TILES_X * TILES_Y);i++) {
			JPanel tmp = new JPanel(new BorderLayout());
			final SingleTileRenderer r = new SingleTileRenderer(tileset.getTile(i + 13), this);
			
			JButton saveButton = new JButton("Save");
			JRadioButton currentButton = new JRadioButton();
			
			tileRadioButtons.add(currentButton);
			tileButtonGroup.add(currentButton);
			
			if (i == 0) {
				currentButton.setSelected(true);
			}
			final int ci = i;
			currentButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					currentIndex = ci;
					updateColBoxes();
				}
			});
			
			final JLabel indexLabel = new JLabel("#" + r.getTileData().index);
			
			r.addActionListener(new ActionListener() {

				public void actionPerformed(ActionEvent e) {
					indexLabel.setText("#" + r.getTileData().index);
				}
				
			});
			
			saveButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					r.saveData();
					if (parent != null) {
//						parent.validate();
//						parent.repaint();
					}
					repaint();
				}
			});
			
			JPanel tmp2 = new JPanel(new BorderLayout());
			tmp2.add(saveButton, BorderLayout.EAST);
			tmp2.add(indexLabel, BorderLayout.CENTER);
			tmp2.add(currentButton, BorderLayout.WEST);
			
			
			if (i < TILES_X) {
				tmp.add(tmp2, BorderLayout.NORTH);
				tmp.add(r, BorderLayout.CENTER);
			} else {
				tmp.add(tmp2, BorderLayout.SOUTH);
				tmp.add(r, BorderLayout.CENTER);
			}
			
			tmp.setBorder(BorderFactory.createEtchedBorder());
			
			tileMatrix.add(tmp);
			tileList.add(r);
		}
		// --------------------------------------- //
		
		tilePanel.add(tileMatrix, BorderLayout.CENTER);
		tilePanel.add(saveAllButton, BorderLayout.SOUTH);
		tilePanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Edit tiles"));
		
		// --------------- Buttons --------------- //
		JPanel bPanel = new JPanel(new GridLayout(7, 1));
		
		bPanel.add(replaceColorButton);
		bPanel.add(addTilesButton);
		bPanel.add(removeTilesButton);
		bPanel.add(flipTileHorizontalButton);
		bPanel.add(flipTileVerticalButton);
		bPanel.add(copyTileButton);
		bPanel.add(pasteTileButton);
		
		tool2Panel.add(bPanel, BorderLayout.NORTH);
		// ---------------------------------------- //
		
		// --------------- Collision -------------- //
		colPanel.add(colIndexLabel);
		colPanel.add(nColBox);
		colPanel.add(sColBox);
		colPanel.add(wColBox);
		colPanel.add(eColBox);
		colPanel.add(jumpColBox);
		colPanel.add(waterColBox);
		colPanel.add(saveColButton);
		saveColButton.addActionListener(this);
		colPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Collision"));
		colIndexLabel.setBorder(BorderFactory.createEtchedBorder());
		// ---------------------------------------- //
		
		
		tool1Panel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Palette"));
		tool2Panel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Tools"));
		
		JPanel tmp = new JPanel(new BorderLayout());
		tmp.add(tilePanel, BorderLayout.SOUTH);
		tmp.add(autoChangeTileBox, BorderLayout.NORTH);
		autoChangeTileBox.setBorder(BorderFactory.createEtchedBorder());
		
		add(tmp, BorderLayout.WEST);
		add(tool1Panel, BorderLayout.SOUTH);
		
		tmp = new JPanel(new GridLayout(1, 2));
		tmp.add(colPanel);
		tmp.add(tool2Panel);
		
		add(tmp, BorderLayout.EAST);
		
		updateColBoxes();
	}
	
	public void updateColBoxes() {
		TileData td = tileList.get(currentIndex).getTileData();
		
		colIndexLabel.setText("<html>Tile: " + td.index + " / " + 
				String.format("0x%X", td.index) + "</html>");
		
		nColBox.setSelected(td.collInfo.north);
		sColBox.setSelected(td.collInfo.south);
		wColBox.setSelected(td.collInfo.west);
		eColBox.setSelected(td.collInfo.east);
		jumpColBox.setSelected(td.collInfo.jump);
		waterColBox.setSelected(td.collInfo.water);
	}
	
	public void replaceColor(Color oldColor, Color newColor) {
		for (TileData element: tileset.getTiles()) {
			char[] pixels = element.pixels;
			
			for (int i = 0;i < pixels.length;i++) {
				Color c = Tools.getColor(pixels[i] & 0x000F);
				if (c.getRGB() == oldColor.getRGB()) {
					pixels[i] = (char)((pixels[i] & 0xFFF0) | Tools.getColorIndex(newColor));
				}
				
				c = Tools.getColor(pixels[i] >>> 4);
				if (c.getRGB() == oldColor.getRGB()) {
					pixels[i] = (char)((pixels[i] & 0x000F) | (Tools.getColorIndex(newColor) << 4));
				}
			}
		}
		
		if (parent != null) {
			parent.validate();
		}
		repaint();
	}
	
	public Color getCurrentColor() {
		return currentColor.getBackground();
	}
	
	public void setCurrentColor(Color c) {
		currentColor.setBackground(c);
	}

	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == tilesetPanel) {
			tileList.get(currentIndex).setTile(tilesetPanel.getCurrentTile());
			
			if (!autoChangeTileBox.isSelected()) {
				updateColBoxes();
				return;
			}
			currentIndex++;
			if (currentIndex == (TILES_X * TILES_Y)) {
				currentIndex = 0;
			}
			tileRadioButtons.get(currentIndex).setSelected(true);
			updateColBoxes();
		} else if (e.getSource() == saveAllButton) {
			for (SingleTileRenderer r: tileList) {
				r.saveData();
			}
			
			if (parent != null) {
//				parent.validate();
//				parent.repaint();
			}
			repaint();
		} else if (e.getSource() == replaceColorButton) {
			replaceDialog = new ColorReplaceDialog(parent);
			replaceDialog.addActionListener(this);
			
		} else if(e.getSource() == addTilesButton) {
			MainWindow mw = null;
			
			if (parent instanceof MainWindow) {
				mw = (MainWindow)parent;
			} else {
				return;
			}
			
			String a = JOptionPane.showInputDialog(this, 
					"<html>Enter the number of tiles to add.</html>",
					"Add tiles",  
					JOptionPane.OK_CANCEL_OPTION);
			
			if (a == null) {
				return;
			}
			
			int n;
			
			try {
				Scanner sc = new Scanner(a);
				n = sc.nextInt();
			} catch (Exception exc) {
				JOptionPane.showMessageDialog(this, "Bad input. Please check what you " +
						"have typed and try again.");
				return;
			}
			
			mw.addEmptyTiles(n);
			
		} else if(e.getSource() == removeTilesButton) {
			MainWindow mw = null;
			
			if (parent instanceof MainWindow) {
				mw = (MainWindow)parent;
			} else {
				return;
			}
			
			String a = JOptionPane.showInputDialog(this, 
					"<html>Enter the number of tiles to remove.</html>",
					"Remove tiles",  
					JOptionPane.OK_CANCEL_OPTION);
			
			if (a == null) {
				return;
			}
			
			int n;
			
			try {
				Scanner sc = new Scanner(a);
				n = sc.nextInt();
			} catch (Exception exc) {
				JOptionPane.showMessageDialog(this, "Bad input. Please check what you " +
						"have typed and try again.");
				return;
			}
			
			mw.removeTiles(n);
			
		} else if (e.getSource() == replaceDialog) {
			replaceColor(replaceDialog.getOldColor(), replaceDialog.getNewColor());
		} else if (e.getSource() == saveColButton) {
			TileData td = tileList.get(currentIndex).getTileData();
			
			td.collInfo.north = nColBox.isSelected();
			td.collInfo.south = sColBox.isSelected();
			td.collInfo.west = wColBox.isSelected();
			td.collInfo.east = eColBox.isSelected();
			td.collInfo.jump = jumpColBox.isSelected();
			td.collInfo.water = waterColBox.isSelected();
			
			repaint();
		} else if (e.getSource() == flipTileVerticalButton) {
			SingleTileRenderer str = tileList.get(currentIndex);
			str.flipTileY();
		} else if (e.getSource() == flipTileHorizontalButton) {
			SingleTileRenderer str = tileList.get(currentIndex);
			str.flipTileX();
		} else if (e.getSource() == copyTileButton) {
			SingleTileRenderer str = tileList.get(currentIndex);
			this.pixelData = str.copyPixelData();
		} else if (e.getSource() == pasteTileButton) {
			SingleTileRenderer str = tileList.get(currentIndex);
			if(pixelData != null){
				str.pastePixelData(pixelData);
			}
			
		}
	}
}








